/**
@file	
	mapper.h
@brief	
	mapper.
@author
	GengYong
@revision
	2005/10/27 * Created by GengYong.
*/

#ifndef MMONETWORK_HEADERFILE_MAPPER_H
#define MMONETWORK_HEADERFILE_MAPPER_H

namespace MMONetwork
{
	namespace Utility
	{
		template <typename T>
		class mapper
		{
		private:
			typedef struct _LEAF
			{
				unsigned long count;
				union 
				{
					_LEAF * _node[256];
					T	  * _var[256];
				} content;
			} _LEAF;
		public:
			inline mapper(unsigned int count = 32)
			{
				if (count == 0) count = 1;
				_count = count;
				_capacity = count;
				count *= 4;

				try
				{
					_val_buf = new T[_count];
					_leaf_buf = new _LEAF[count];
					_unused_val = (T**) new char[sizeof(T*) * _count];
					_unused_leaf = (_LEAF**) new char[sizeof(_LEAF*) * count];
					for (unsigned int i = 0; i < _count; i++)
					{
						_unused_val[i] = &(_val_buf[i]);
					}
					
					
					for (unsigned int i = 0 ; i < count; i++)
					{
						_leaf_buf[i].count = 0;
						for (unsigned int k = 0; k < 256; k++)
						{
							_leaf_buf[i].content._node[k] = 0;
						}
					}
					for (unsigned int i = 0; i < count; i++)
					{
						_unused_leaf[i] = &(_leaf_buf[i]);
					}

					_leaf_idx = _unused_leaf;
					_val_idx = _unused_val;
				}
				catch(...)
				{
					throw;
				}
				return;
			}
			inline ~mapper()
			{
				delete[] (const char*)_unused_leaf;
				delete[] (const char*)_unused_val;
				delete[] _val_buf;
				delete[] _leaf_buf;
			}
		public:
			inline bool insert(unsigned long index, const T& val)
			{
				if (!_count) return false;
				unsigned char * bytes = (unsigned char*)(&index);
				_LEAF ** point0 = 0;
				_LEAF ** point1 = 0;
				_LEAF ** point2 = 0;
				point0 = &(_leaf_buf->content._node[bytes[0]]);
				if (*point0 == 0)
				{
					//ok
					_leaf_buf->count++;
					*point0 = *(++_leaf_idx);
					(*point0)->count = 1;
					point1 = &((*point0)->content._node[bytes[1]]);
					*point1 = *(++_leaf_idx);
					(*point1)->count = 1;
					point2 = &((*point1)->content._node[bytes[2]]);
					*point2 = *(++_leaf_idx);
					(*point2)->count = 1;
					T ** t = &((*point2)->content._var[bytes[3]]);
					*t = *(_val_idx++);
					**t = val;
					--_count;
					return true;
				}
				point1 = &((*point0)->content._node[bytes[1]]);
				if (*point1 == 0)
				{
					//ok
					(*point0)->count++;
					*point1 = *(++_leaf_idx);
					(*point1)->count = 1;
					point2 = &((*point1)->content._node[bytes[2]]);
					*point2 = *(++_leaf_idx);
					(*point2)->count = 1;
					T ** t = &((*point2)->content._var[bytes[3]]);
					*t = *(_val_idx++);
					**t = val;
					--_count;
					return true;
				}
				point2 = &((*point1)->content._node[bytes[2]]);
				if (*point2 == 0)
				{
					//ok
					(*point1)->count++;
					*point2 = *(++_leaf_idx);
					(*point2)->count = 1;
					T ** t = &((*point2)->content._var[bytes[3]]);
					*t = *(_val_idx++);
					**t = val;
					--_count;
					return true;
				}
				T ** t = &((*point2)->content._var[bytes[3]]);
				if (*t == 0)
				{
					(*point2)->count++;
					*t = *(_val_idx++);
					**t = val;
					--_count;
					return true;
				}
				return false;
			}

			inline void remove(unsigned long index)
			{
				unsigned char * bytes = (unsigned char*)(&index);
				_LEAF ** point0 = 0;
				_LEAF ** point1 = 0;
				_LEAF ** point2 = 0;
				if (0 != (*(point0 = &(_leaf_buf->content._node[bytes[0]]))))
				if (0 != (*(point1 = &((*point0)->content._node[bytes[1]]))))
				if (0 != (*(point2 = &((*point1)->content._node[bytes[2]]))))
				if (0 != ((*point2)->content._var[bytes[3]]))
				{
					++_count;
					*(--_val_idx) = (*point2)->content._var[bytes[3]];
					(*point2)->content._var[bytes[3]] = 0;
					if (!(--(*point2)->count))
					{
						*(_leaf_idx--) = *point2; *point2 = 0;
						if (!(--(*point1)->count))
						{
							*(_leaf_idx--) = *point1; *point1 = 0;
							if (!(--(*point0)->count))
							{
								*(_leaf_idx--) = *point0; *point0 = 0;
								--_leaf_buf->count;
							}
						}
					}
				}
				return;
			}

			inline void replace(unsigned long index, const T& val)
			{
				if (!insert(index, val))
				{
					remove(index);
					insert(index, val);
				}
				return;
			}

			inline bool move(unsigned long index, unsigned long newindex)
			{
				T val;
				if (getlink(index, val))
				{
					remove(index);
					return insert(newindex, val);
				}
				return false;
			}
			
			inline bool getlink(unsigned long index, T& ret) const
			{			
				unsigned char * bytes = (unsigned char *)(&index);
				_LEAF * p = 0;				
				if ((p = (_leaf_buf->content._node[*bytes++]))
				&& (p = ((p)->content._node[*bytes++]))
				&& (p = ((p)->content._node[*bytes++])))
				{
					ret = *((p)->content._var[*bytes]);
					return true;
				}
				return false;
			}

			inline unsigned long count() const
			{
				return (_capacity - _count);
			}


		private:
			T		*	_val_buf;
			T		**	_val_idx;
			T		**	_unused_val;
			_LEAF	*	_leaf_buf;
			_LEAF	**	_leaf_idx;
			_LEAF	**	_unused_leaf;
			unsigned long _count;
			unsigned long _capacity;
		};
	}
}


#endif	//#ifndef MMONETWORK_HEADERFILE_MAPPER_H
